/**
  ******************************************************************************
  * @file    sh30f9xx_sa0_pca.c
  * @author  sinowealth
  * @version V1.1.0
  * @date    2021-01-06  
  * @brief   This file provides firmware functions to manage the following 
  *         
  *  @verbatim
  *
  *          ===================================================================
  *                                   How to use this driver
  *          ===================================================================
  *
  *  @endverbatim
  *
  ******************************************************************************
  * @attention
  *
  * SINOWEALTH IS SUPPLYING THIS SOFTWARE FOR USE EXCLUSIVELY SH_ON SINOWEALTH'S 
  * MICROCONTROLLER PRODUCTS. IT IS PROTECTED UNDER APPLICABLE COPYRIGHT LAWS. 
  * THIS SOFTWARE IS FOR GUIDANCE IN ORDER TO SAVE TIME. AS A RESULT, SINOWEALTH 
  * SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES 
  * WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT OF SUCH FIRMWARE AND/OR
  * THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION CONTAINED HEREIN IN 
  * CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2021 Sinowealth</center></h2>
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "sh30f9xx_sa0_pca.h"

/** @addtogroup SH30F9xx_sa0_libcfg_StdLib_Driver
  * @{
  */

/** @defgroup PCA_MODULE PCA 
  * @brief PCA driver modules
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/** @defgroup PCA_Private_Functions
  * @{
  */

/** @defgroup PPP_Group1 Initialization and Configuration
 *  @brief    Initialization and Configuration
 *
@verbatim    
 ===============================================================================
                      Initialization and Configuration
 ===============================================================================  
   
@endverbatim
  * @{
  */

/**
  * @brief  Fills each PCA_InitStruct member with its default value.
  * @param  PCA_InitStruct : pointer to a PCA_InitTypeDef structure which will
  *         be initialized.
  * @retval None
  */
void PCA_StructInit(PCA_InitTypeDef *PCA_InitStruct)
{
    PCA_InitStruct->PCA_CFGR.ClkSel = PCLK0;
    PCA_InitStruct->PCA_CFGR.PCACounterMode = SINGLEEDGE;
    PCA_InitStruct->PCA_CFGR.CCR0UPDATAEN = SH_DISABLE;
    PCA_InitStruct->PCA_CFGR.CCR1UPDATAEN = SH_DISABLE;
    PCA_InitStruct->PCA_CFGR.PUEUPDATAEN = SH_DISABLE;
    PCA_InitStruct->PCA_CFGR.ECFSel = FILTERING_NONE;
    PCA_InitStruct->PCA_CFGR.rev1 = 0;
    PCA_InitStruct->PCA_CFGR.rev2 = 0;
    PCA_InitStruct->PCA_CFGR.rev3 = 0;
    PCA_InitStruct->PCA_CFGR.rev4 = 0;

    PCA_InitStruct->PCA_CCMR0.PCA_CC = SH_DISABLE;
    PCA_InitStruct->PCA_CCMR0.ModeSelect = CAPTUREMODE;
    PCA_InitStruct->PCA_CCMR0.FunctionSelect = RISING_EDGE_TRIGGER;
    PCA_InitStruct->PCA_CCMR0.PCA_CEN = SH_DISABLE;
    PCA_InitStruct->PCA_CCMR0.PCA_TCP = SH_DISABLE;
    PCA_InitStruct->PCA_CCMR0.rev5 = 0;
    PCA_InitStruct->PCA_CCMR0.rev6 = 0;

    PCA_InitStruct->PCA_CCMR1.PCA_CC = SH_DISABLE;
    PCA_InitStruct->PCA_CCMR1.ModeSelect = CAPTUREMODE;
    PCA_InitStruct->PCA_CCMR1.FunctionSelect = RISING_EDGE_TRIGGER;
    PCA_InitStruct->PCA_CCMR1.PCA_CEN = SH_DISABLE;
    PCA_InitStruct->PCA_CCMR1.PCA_TCP = SH_DISABLE;
    PCA_InitStruct->PCA_CCMR1.rev5 = 0;
    PCA_InitStruct->PCA_CCMR1.rev6 = 0;

    PCA_InitStruct->PCA_FORCE = 0;
    PCA_InitStruct->PCA_CNT = 0;
    PCA_InitStruct->PCA_PSC = 0;

    PCA_InitStruct->PCA_PR = 0;

    PCA_InitStruct->PCA_CCR0 = 0;
    PCA_InitStruct->PCA_CCR1 = 0;
}

/**
  * @brief  Initializes the PCAx peripheral according to the specified parameters 
  *         in the PCA_InitStruct.
  * @param  PCAx: where x can be  0 to 3 to select the PCA peripheral.
  * @param  PCA_InitStruct: pointer to a @ref PCA_InitTypeDef structure that contains 
  *         the configuration information for the specified PCA peripheral.
  * @retval None
  */
void PCA_Init(PCA_TypeDef *PCAx, const PCA_InitTypeDef *PCA_InitStruct)
{
    static uint8_t *pv = 0;
    /* check the parameters */
    assert_param(IS_PCA_ALL_PERIPH(PCAx));

    assert_param(IS_PCACLKSOURCE_DIV(PCA_InitStruct->PCA_CFGR.ClkSel));
    assert_param(IS_PCACOUNTERMODE_DIV(PCA_InitStruct->PCA_CFGR.PCACounterMode));

    pv = (uint8_t *)PCA_InitStruct;
    PCAx->LCKR = 0x33CC;
    PCAx->CFGR.V32  = *((uint32_t *)(pv + 0));
    PCAx->FORCE.V32 = *((uint32_t *)(pv + 4));
    PCAx->CNT.V32   = *((uint32_t *)(pv + 8));
    PCAx->PSC       = *((uint32_t *)(pv + 12));
    PCAx->PR.V32    = *((uint32_t *)(pv + 16));
    PCAx->CCMR0.V32 = *((uint32_t *)(pv + 20));
    PCAx->CCMR1.V32 = *((uint32_t *)(pv + 24));
    PCAx->CCR0.V32  = *((uint32_t *)(pv + 28));
    PCAx->CCR1.V32  = *((uint32_t *)(pv + 32));
    PCAx->LCKR = 0;
}

/**
  * @brief  Open or close the PCA peripheral.
  * @param  PCAx: where x can be 0 to 3 to select the PCA peripheral.
  * @param  OnOffState: state of the PCA peripheral.
  *         This parameter can be one of the following values:
  *            @arg SH_ON
  *            @arg SH_OFF
  * @retval None
  */
void PCA_OnOff(PCA_TypeDef *PCAx, CmdState OnOffState)
{
    /* check the parameters */
    assert_param(IS_PCA_ALL_PERIPH(PCAx));
    assert_param(IS_CMD_STATE(OnOffState));

    PCAx->LCKR = 0x33CC;
    if (OnOffState != SH_OFF)
    {
        PCAx->CR = PCA_CR_PEN_Msk;
    }
    else
    {
        PCAx->CR = (~PCA_CR_PEN_Msk);
    }
    PCAx->LCKR = 0;
}

/**
  * @brief  Open or close the PCA cascade.
  * @param  PCAx:where x can be 0 to 3 to select the PCA peripheral.
  * @param  OnOffState: state of the Cascade PCA peripheral.
  *         This parameter can be one of the following values:
  *            @arg SH_ON
  *            @arg SH_OFF
  * @retval None
  */
void PCA_CascadeOnOff(PCA_TypeDef *PCAx, CmdState OnOffState)
{
    /* check the parameters */
    assert_param(IS_PCA_CASCADE_PERIPH(PCAx));
    assert_param(IS_CMD_STATE(OnOffState));

    PCAx->LCKR = 0x33CC;
    if (OnOffState != SH_OFF)
    {
        PCAx->CFGR.V32 |= PCA_CFGR_CASCEN_Msk;
    }
    else
    {
        PCAx->CFGR.V32 &= (~PCA_CFGR_CASCEN_Msk);
    }
    PCAx->LCKR = 0;
}

/**
  * @brief  Set the PCAx Frequency output mode frequency value
  * @param  PCAx: where x can be 0 to 3 to select the PCA peripheral.
*           Channel: Specifie the PCA Channel to Set.
  *         This parameter can be any combination of the following values:
  *            @arg PCA_CHANNEL_A
  *            @arg PCA_CHANNEL_B
  *         Value:Specifie the PCA CPHx to set.
  * @retval None
  */
void PCA_FreqOutValue(PCA_TypeDef *PCAx, PCA_CHANEEL_Type PCAChannel, uint8_t Value)
{
    /* check the parameters */
    assert_param(IS_PCA_ALL_PERIPH(PCAx));
    assert_param(IS_PCACHANEEL_CHANNEL(PCAChannel));

    PCAx->LCKR = 0x33CC;
    if (PCA_CHANNEL_A == PCAChannel)
    {
        PCAx->CCR0.BIT.CCR0H = (uint8_t)Value;
    }
    else
    {
        PCAx->CCR1.BIT.CCR1H = (uint8_t)Value;
    }
    PCAx->LCKR = 0;
}

/**
  * @brief  Set the PCAx Forced match control bit
  * @param  PCAx: where x can be 0 to 3 to select the PCA peripheral.
*           Channel: Specifie the PCA Channel to Set.
  *         This parameter can be any combination of the following values:
  *            @arg PCA_CHANNEL_A
  *            @arg PCA_CHANNEL_B
  *         OnOffState:Switch status.
  *         This parameter can be any combination of the following values:
  *            @arg SH_ON
  *            @arg SH_OFF
  * @retval None
  */
void PCA_ForceMatchControl(PCA_TypeDef *PCAx, PCA_CHANEEL_Type PCAChannel, CmdState OnOffState)
{
    /* check the parameters */
    assert_param(IS_PCA_ALL_PERIPH(PCAx));
    assert_param(IS_PCACHANEEL_CHANNEL(PCAChannel));
    assert_param(IS_CMD_STATE(OnOffState));

    PCAx->LCKR = 0x33CC;
    if (PCA_CHANNEL_A == PCAChannel)
    {
        if (OnOffState != SH_OFF)
        {
            PCAx->FORCE.V32 |= PCA_FORCE_FCO0_Msk;
        }
        else
        {
            PCAx->FORCE.V32 &= (~PCA_FORCE_FCO0_Msk);
        }
    }
    else
    {
        if (OnOffState != SH_OFF)
        {
            PCAx->FORCE.V32 |= PCA_FORCE_FCO1_Msk;
        }
        else
        {
            PCAx->FORCE.V32 &= (~PCA_FORCE_FCO1_Msk);
        }
    }
    PCAx->LCKR = 0;
}

/**
  * @brief  Set the PCAx PR Register value
  * @param  PCAx: where x can be 0 to 3 to select the PCA peripheral.
*           Value: Specifie the PCA PR to Set.
  * @retval Counter Register value
  * @retval None
  */
void PCA_SetPRValue(PCA_TypeDef *PCAx, uint32_t Value)
{
    /* check the parameters */
    assert_param(IS_PCA_ALL_PERIPH(PCAx));

    PCAx->LCKR   = 0x33CC;
    PCAx->PR.V32 = (uint32_t)Value;
    PCAx->LCKR   = 0;
}

/**
  * @brief  Set the PCAx CCR Register value
  * @param  PCAx: where x can be 0 to 3 to select the PCA peripheral.
  *         Channel: Specifie the PCA Channel to set.
  *         This parameter can be any combination of the following values:
  *            @arg PCA_CHANNEL_A
  *            @arg PCA_CHANNEL_B
  *         Value:Specifie the PCA CCRx to set.
  * @retval None
  */
void PCA_SetCCRValue(PCA_TypeDef *PCAx, PCA_CHANEEL_Type PCAChannel, uint32_t Value)
{
    /* check the parameters */
    assert_param(IS_PCA_ALL_PERIPH(PCAx));
    assert_param(IS_PCACHANEEL_CHANNEL(PCAChannel));

    PCAx->LCKR = 0x33CC;
    if (PCA_CHANNEL_A == PCAChannel)
    {
        PCAx->CCR0.V32 = Value;
    }
    else
    {
        PCAx->CCR1.V32 = Value;
    }
    PCAx->LCKR = 0;
}

/**
  * @brief  Get the PCAx CCR Register value
  * @param  PCAx: where x can be 0 to 3 to select the PCA peripheral.
*           Channel: Specifie the PCA Channel to set.
  *         This parameter can be any combination of the following values:
  *            @arg PCA_CHANNEL_A
  *            @arg PCA_CHANNEL_B
  * @retval CPR_Count
  */
uint32_t PCA_GetCaptureValue(PCA_TypeDef *PCAx, PCA_CHANEEL_Type PCAChannel)
{
    static uint32_t CCR_Count = 0;
    /* check the parameters */
    assert_param(IS_PCA_ALL_PERIPH(PCAx));
    assert_param(IS_PCACHANEEL_CHANNEL(PCAChannel));

    if (PCA_CHANNEL_A == PCAChannel)
    {
        CCR_Count = PCAx->CCR0.V32;
    }
    else
    {
        CCR_Count = PCAx->CCR1.V32;
    }

    return CCR_Count;
}

/**
  * @brief  Check whether the specified PCA flag is set or not.
  * @param  PCAx: where x can be 0 to 3 to select the PCA peripheral.
  * @param  PCA_IntFlag: Specifie the flag to check.
  *         This parameter can be any combination of the following values:
  *            @arg PCA_FLAG_CC0IF  
  *            @arg PCA_FLAG_CC1IF
  *            @arg PCA_FLAG_PIF
  *            @arg PCA_FLAG_CIF
  * @retval The new state of PCAx's flag.
  */
FlagStatus PCA_GetFlagStatus(PCA_TypeDef *PCAx, uint16_t PCA_IntFlag)
{
    FlagStatus bitStatus;
    /* check the parameters */
    assert_param(IS_PCA_ALL_PERIPH(PCAx));
    assert_param(IS_PCA_GET_ONE_FLAG(PCA_IntFlag));
    if ((PCAx->SR.V32 & PCA_IntFlag) != SH_RESET)
    {
        bitStatus = SH_SET;
    }
    else
    {
        bitStatus = SH_RESET;
    }

    return bitStatus;
}
/**
  * @brief  Get the status of the trigger level in the capture mode.
  * @param  PCAx: where x can be 0 to 3 to select the PCA peripheral.
  * @param  Channel: Specifie the PCA Channel to Set.
  *         This parameter can be any combination of the following values:
  *            @arg PCA_CHANNEL_A
  *            @arg PCA_CHANNEL_B
  * @retval CCMR_TCP
  */
FlagStatus PCA_GetCapterLevelStatus(PCA_TypeDef *PCAx, PCA_CHANEEL_Type PCAChannel)
{
    FlagStatus bitStatus;
    /* check the parameters */
    assert_param(IS_PCA_ALL_PERIPH(PCAx));
    assert_param(IS_PCACHANEEL_CHANNEL(PCAChannel));

    if (PCA_CHANNEL_A == PCAChannel)
    {
        bitStatus = (FlagStatus)PCAx->CCMR0.BIT.TCP;
    }
    else
    {
        bitStatus = (FlagStatus)PCAx->CCMR1.BIT.TCP;
    }

    return bitStatus;
}

/**
  * @brief  Clear the PCA's pending flags.
  * @param  PCAx: where x can be 0 to 3 to select the PCA peripheral.
  * @param  PCA_IntFlag: Specifie the flag to check.
  *         This parameter can be any combination of the following values:
  *            @arg PCA_FLAG_CC0IF  
  *            @arg PCA_FLAG_CC1IF
  *            @arg PCA_FLAG_PIF
  *            @arg PCA_FLAG_CIF
  * @retval None
  */
void PCA_ClearFlag(PCA_TypeDef *PCAx, uint16_t PCA_IntFlag)
{
    /* Check the parameters */
    assert_param(IS_PCA_ALL_PERIPH(PCAx));
    assert_param(IS_PCA_GET_ONE_FLAG(PCA_IntFlag));

    PCAx->LCKR    = 0x33CC;
    PCAx->SR.V32 |= ((uint32_t)PCA_IntFlag << 16);
    PCAx->LCKR    = 0;
}
/**
  * @brief  Clear the PCAx's All pending flag.
  * @param  PCAx: where x can be 0 to 3 to select the PCA peripheral.
  * @retval None
  */
void PCA_ClearAllFlag(PCA_TypeDef *PCAx)
{
    /* check the parameters */
    assert_param(IS_PCA_ALL_PERIPH(PCAx));

    PCAx->LCKR = 0x33CC;
    PCAx->SR.V32 = PCA_SR_CC0IFC_Msk | PCA_SR_CC1IFC_Msk \
                   | PCA_SR_PIFC_Msk | PCA_SR_CIFC_Msk;
    PCAx->LCKR = 0;
}

/**
  * @brief  Enable or disable the specified PCA's interrupts.
  * @param  PCAx: where x can be 0 to 3 to select the PCA peripheral.
  * @param  IntSource: PCA Interrupt source.
  *         This parameter can be one of the following values:
  *            @arg PCA_COUNTER_OVERFLOW_INT
  *            @arg PCA_COUNTER_CYCLE_INT
  * @param  NewState: New state of PCA interrupt.
  *         This parameter can be one of the following values:
  *            @arg SH_ENABLE
  *            @arg SH_DISABLE
  * @retval None
  */
void PCA_INTConfig(PCA_TypeDef *PCAx, uint32_t IntSource, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_PCA_ALL_PERIPH(PCAx));
    assert_param(IS_PCA_INT_SOURCE(IntSource));
    assert_param(IS_FUNCTION_STATE(NewState));

    PCAx->LCKR = 0x33CC;
    if (NewState != SH_DISABLE)
    {
        PCAx->CFGR.V32 |= IntSource;
    }
    else
    {
        PCAx->CFGR.V32 &= (~IntSource);
    }
    PCAx->LCKR = 0;
}

/**
  * @brief  Enable or disable the specified PCAx Capture's interrupts.
  * @param  PCAx: where x can be 0 to 3 to select the PCA peripheral.
  * @param  PCAChannel: channel of PCA Capture's interrupt.
  *         This parameter can be one of the following values:
  *            @arg PCA_CHANNEL_A
  *            @arg PCA_CHANNEL_B
  * @param  NewState: New state of PCA interrupt.
  *         This parameter can be one of the following values:
  *            @arg SH_ENABLE
  *            @arg SH_DISABLE
  * @retval None
  */
void PCA_CapINTConfig(PCA_TypeDef *PCAx, PCA_CHANEEL_Type PCAChannel, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_PCA_ALL_PERIPH(PCAx));
    assert_param(IS_PCACHANEEL_CHANNEL(PCAChannel));
    assert_param(IS_FUNCTION_STATE(NewState));

    PCAx->LCKR = 0x33CC;
    if (PCA_CHANNEL_A == PCAChannel)
    {
        if (NewState != SH_DISABLE)
        {
            PCAx->CCMR0.V32 |= PCA_CCMR0_CCIE_Msk;
        }
        else
        {
            PCAx->CCMR0.V32 &= (~PCA_CCMR0_CCIE_Msk);
        }
    }
    else
    {
        if (NewState != SH_DISABLE)
        {
            PCAx->CCMR1.V32 |= PCA_CCMR1_CCIE_Msk;
        }
        else
        {
            PCAx->CCMR1.V32 &= (~PCA_CCMR1_CCIE_Msk);
        }
    }
    PCAx->LCKR = 0;
}

/**
  * @brief  Enable or disable the PCA's DMA request sources.
  * @param  PCAx: where x can be 0 to 3 to select the PCA peripheral.
  * @param  PCA_DMASource: specifies the DMA request.
  *         This parameter can be any combination of the following values:
  *            @arg PCA_DMA_CYCLE_MATCH
  *            @arg PCA_DMA_CntOverflow
  *            @arg PCA_DMA_Channel_0
  *            @arg PCA_DMA_Channel_1
  * @param  NewState: new state of the DMA Request sources.
  *         This parameter can be one of the following values:
  *            @arg SH_ENABLE
  *            @arg SH_DISABLE
  * @retval None
  */
void PCA_DMAConfig(PCA_TypeDef *PCAx, uint32_t PCA_DMASource, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_PCA_ALL_PERIPH(PCAx));
    assert_param(IS_PCA_Trg_SOURCE(PCA_DMASource));
    assert_param(IS_FUNCTION_STATE(NewState));

    PCAx->LCKR = 0x33CC;
    if (NewState != SH_DISABLE)
    {
        /* Enable the PCA's DMA request sources */
        PCAx->CFGR.V32 |= PCA_DMASource;
    }
    else
    {
        /* Disable the PCA's DMA request sources */
        PCAx->CFGR.V32 &= (~PCA_DMASource);
    }
    PCAx->LCKR = 0;
}

/************************ (C) COPYRIGHT Sinowealth *****END OF FILE****/
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                